package org.jackysoft.service;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.jackysoft.data.AbstractDataProvider;
import org.jackysoft.entity.Identifiable;
import org.jackysoft.entity.nosql.OperationLog;
import org.jackysoft.util.CollectionUtils;
import org.jackysoft.util.FileInfo;
import org.jackysoft.util.OperationType;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.mongodb.DBObject;

public abstract class AbstractServiceImpl<ID extends Serializable,B extends Identifiable>
extends AbstractDataProvider<ID,B> implements ResourceLoaderAware{

	
	
	protected ResourceLoader resourceLoader;
	protected OperationLogService  logService;
	protected SecurityRoleNotifyService notifyService;
    /**
	 * 
	 */
	private static final long serialVersionUID = -8116000530953092036L;
	public AbstractServiceImpl() {super();}
	public AbstractServiceImpl(Class<B> type) {
		super(type);
	}

	protected Collection<B> getsByHql(String hql) throws DataAccessException {
		Session session = getSession();

		Collection<B> crat = null;
		try {
			if (hql == null)
				return Collections.emptyList();
			crat = session.createQuery(hql).list();

		} catch (DataAccessException e) {
			e.printStackTrace();
			log.error(e.toString());
		}
		return crat;
	}

	protected Collection<B> getsByExample(B t) {
		Example example = Example.create(t);
		return getSession().createCriteria(this.type).add(example).list();

	}
	
	public String FromCLause(){
		return "from "+this.table()+" ";
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public Collection<B> gets() throws DataAccessException {
		Session session = getSession();
		Query q = session.createQuery(FromCLause());
		return q.list();
	}
	
	
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void create(B b) throws DataAccessException {
		Session session = getSession();
		session.save(b);
		
	}
	
	
	@Override
	public void create(Collection<B> bs) throws DataAccessException {
		CollectionUtils.notNullable(bs);
		int total = bs.size();
		Session sess = getSession();
		int count = 0;
		Iterator<B> itr = bs.iterator();
		while (itr.hasNext()) {
			B b = itr.next();
			if(b==null)continue;
			sess.save(b);
			if (++count % 20 == 0 && total>20) {
				sess.flush();
				sess.clear();
			}

		}
		if(total<20){
			sess.flush();
			sess.clear();
		}
		
	}
	
	
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void remove(B t) throws DataAccessException {

		Session session = getSession();
		session.delete(t);
		
		
	}	
	
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void remove(Collection<B> bs) throws DataAccessException {
		Session sess = getSession();
		int count = 0;
		Iterator<B> itr = bs.iterator();
		while (itr.hasNext()) {
			B b = itr.next();
			sess.delete(b);
			if (++count % 20 == 0) {
				sess.flush();
				sess.clear();
			}

		}

		
	}
	@Override
	public void update(B b) throws DataAccessException {
		//getSession().evict(b);
		getSession().clear();
		getSession().update(b);
		getSession().flush();
		
	}
	@Override
	public void update(Collection<B> bs) throws DataAccessException {
		Session sess = getSession();
		int count = 0;
		Iterator<B> itr = bs.iterator();
		while (itr.hasNext()) {
			B b = itr.next();
			sess.update(b);
			if (++count % 20 == 0) {
				sess.flush();
				sess.clear();
			}

		}
		
	}
	@Override
	public void saveOrUpdate(B b) throws DataAccessException {
		Session session = getSession();
		session.saveOrUpdate(b);
		
	}
	@Override
	public int count() throws DataAccessException {
		Session session = getSession();
		Object obj = session.createQuery(
				"select count(*) from " + type.getName()).uniqueResult();
		Long icount = obj==null?0L:Long.parseLong(obj.toString());
		return icount.intValue();
	}
	

	
	protected Query query(String hql) throws DataAccessException {
		return getSession().createQuery(hql);
	}
	
	
	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Collection<B> gets(int start, int size) throws DataAccessException {
		Session session = getSession();
		List list = null;  
		//list = session.createCriteria(type).setFirstResult(start).setMaxResults(size).list();
		String hql = String.format(" from %s ",table());
		list = session.createQuery(hql).setFirstResult(start).setMaxResults(size).list();
		return list;
	}
	@Override
	public void setResourceLoader(ResourceLoader arg0) {
		this.resourceLoader = arg0;
		
	}
	public OperationLogService getLogService() {
		return logService;
	}
	
	@Resource
	public void setLogService(OperationLogService logService) {
		this.logService = logService;
	}	
	
	protected OperationLog traceLog(OperationType oprType,String opr,String detail){
		OperationLog oprlog = new OperationLog();
		oprlog.setOprType(oprType);
		oprlog.setCreateDate(new Date());
	    oprlog.setName(opr);
	    oprlog.setDetails(detail);
	    logService.create(oprlog);
		return oprlog;
	}
	@Resource
	public void setNotifyService(SecurityRoleNotifyService notifyService) {
		this.notifyService = notifyService;
	}
	@Override
	public void drop() {
		// TODO Auto-generated method stub
		
	}
	@Override
	public B get(ID id) throws DataAccessException {
		Session session = getSession();
		B t = (B) session.get(this.getType(), id);
		return t;
	}
	@Override
	public B get(DBObject query) throws DataAccessException {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public Collection<B> gets(int start, int size, DBObject sort)
			throws DataAccessException {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public Collection<B> query(int start, int size, DBObject query)
			throws DataAccessException {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public Collection<B> query(int start, int size, DBObject query,
			DBObject sort) throws DataAccessException {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public Collection<B> gets(DBObject query) throws DataAccessException {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public Collection<B> getsAndSort(DBObject query, DBObject sort)
			throws DataAccessException {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public void remove(String id) throws DataAccessException {
		
	}
	@Override
	public void removeAll() throws DataAccessException {
		// TODO Auto-generated method stub
		
	}
	@Override
	public int count(DBObject query) {
		// TODO Auto-generated method stub
		return 0;
	}
	
		
	@Override
	public FileInfo download(String id) throws Exception {
		return  null;		
	}
	@Override
	public Collection<B> batchImport(byte[] data) throws Exception {
		return null;		
	}	
}